# -*- coding: utf8 -*-

from typing import Union, Dict, Any

import argparse
import sys
import os

from os.path import join as joinpath, abspath, normpath
from string import Template

_APP_VERSION = '0.1.0'

_base_path: str = ''
_log_enabled: bool = False


_LOGBACK_SPRING_XML_MAIN = r'''<!-- https://logback.qos.ch/manual/configuration.html#syntax -->
<configuration scan="true">
    <appender name="RollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>log/$name.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>log/$name-%d{yyyyMMdd}-%i.log</fileNamePattern>
            <maxFileSize>5MB</maxFileSize>
            <maxHistory>100</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ssZ} [%-5p] %c{40} \(%F:%L\) - %m%n</pattern>
            <outputPatternAsHeader>true</outputPatternAsHeader>
            <charset>utf-8</charset>
        </encoder>
    </appender>
    <root level="info">
        <appender-ref ref="RollingFile"/>
    </root>
</configuration>
'''

_LOGBACK_SPRING_XML_TEST = r'''<!-- https://logback.qos.ch/manual/configuration.html#syntax -->
<configuration>
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
    <appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%clr(%d{yyyy-MM-dd HH:mm:ssZ}){cyan} [%highlight(%-5p)] %clr(%C{40}){yellow} \(%F:%L\) - %clr(%m){magenta}%n
            </pattern>
        </encoder>
    </appender>
    <root level="debug">
        <appender-ref ref="Console"/>
    </root>
    <logger name="org.apache" level="info"/>
    <logger name="org.apache.commons" level="info"/>
    <logger name="org.springframework" level="info"/>
    <logger name="org.springframework.util" level="info"/>
    <logger name="com.zaxxer.hikari" level="info"/>
</configuration>
'''

_POM_XML = r'''<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>$group</groupId>
    <artifactId>${artifact_id}</artifactId>
    <version>0.1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <java.version>11</java.version>
        <bundle>dev</bundle>
        <skipTests>true</skipTests>
    </properties>
    <build>
        <finalName>$${project.artifactId}-$${bundle}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <!-- 指定启动类 -->
                    <mainClass>$group.${artifact_id}.Application</mainClass>
                    <!-- 指定开发环境下使用的profile -->
                    <profiles>common,$${bundle}</profiles>
                    <!-- 使用/src/resources目录下的文件而不是/target/classes目录下的文件-->
                    <addResources>true</addResources>
                    <!-- 指定绑定IP地址和端口号 -->
                    <arguments>
                        <argument>--server.host=0.0.0.0</argument>
                        <argument>--server.port=8088</argument>
                    </arguments>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <!-- Compile -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.hibernate.validator</groupId>
                    <artifactId>hibernate-validator</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- Test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>junit</groupId>
                    <artifactId>junit</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- Runtime -->
        <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>  
'''


def _parse_args(
    args
) -> argparse.Namespace:
    r''' 解析命令行参数。
    '''
    parser = argparse.ArgumentParser(prog='mvni', add_help=False)
    parser.add_argument('name', action='store', nargs='?', metavar='FULL NAME')
    pg = parser.add_mutually_exclusive_group(required=False)
    pg.add_argument('--help', action='help', help='Show this help message and quit')
    pg.add_argument('--version', action='version', version='%(prog)s ' + _APP_VERSION, help='Show version message and quit')
    pg.add_argument('--debug', action='store_true', help='Show debugging information')

    return parser.parse_args()


def _split_name(
    s: str
):
    np = s.rfind('.')
    if np >= 0:
        return s[:np], s[np + 1:]
    else:
        return '', s


def _mkdir(
    path: str
) -> None:
    global _log_enabled, _base_path
    path = normpath(joinpath(_base_path, path))
    if _log_enabled:
        print('Make directory: {!s}'.format(path))
    os.makedirs(path, exist_ok=True)


def _write_file(
    path: str,
    content: str = '',
    **kwargs
) -> None:
    global _log_enabled, _base_path
    path = normpath(joinpath(_base_path, path))
    if _log_enabled:
        print('Write file: {!s}'.format(path))

    with open(path, 'wt', newline='\n', encoding='utf-8') as f:
        for line in content.splitlines():
            t = Template(line)
            print(t.substitute(kwargs), file=f)


if __name__ == '__main__':
    args = _parse_args(sys.argv)

    group, artifact_id = _split_name(args.name)

    _base_path = normpath(abspath(artifact_id))

    if args.debug:
        _log_enabled = True
        print('Base: {!r:}'.format(_base_path))

    pkg_dirname = args.name.replace('.', '/')

    # 创建main文件夹。
    _mkdir('src/main/java/' + pkg_dirname)
    _mkdir('src/main/resources')
    _mkdir('src/main/scripts')

    # 创建test文件夹。
    _mkdir('src/test/java/' + pkg_dirname)
    _mkdir('src/test/resources')

    # 创建logback.xml
    _write_file('src/main/resources/logback-spring.xml', _LOGBACK_SPRING_XML_MAIN, name=artifact_id)
    _write_file('src/test/resources/logback-spring.xml', _LOGBACK_SPRING_XML_TEST, name=artifact_id)

    # 创建.gitkeep
    _write_file('src/main/scripts/.gitkeep')
    _write_file('src/main/java/' + pkg_dirname + '/.gitkeep')
    _write_file('src/test/java/' + pkg_dirname + '/.gitkeep')

    # 创建pom.xml文件。
    _write_file('pom.xml', _POM_XML, group=group, artifact_id=artifact_id)
